﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using DoeObjects;
using DoeLibsMVC.Security;
using DoeLibsMVC.Models;
using DoeLibsMVC.Filter;

namespace DoeLibsMVC.Controllers.api
{
    public class LoanableController : BaseApiController
    {
        /// <summary>
        /// returns all loanables
        /// </summary>
        /// <returns></returns>
        public HttpResponseMessage Get()
        {
            return Request.CreateResponse<IEnumerable<Loanable>>(HttpStatusCode.OK, Loanable.getAllLoanables());
        }    

        /// <summary>
        /// returns information about a loanable
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public HttpResponseMessage Get(int id)
        {
            Loanable loanable = Loanable.getById(id);

            if (loanable != null)
            {
                return Request.CreateResponse<Loanable>(HttpStatusCode.OK, loanable);
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
        }

        /// <summary>
        /// returns all loanables owned by the current user
        /// </summary>
        /// <param name="onlyMine"></param>
        /// <returns></returns>
        [Security.BasicAuthorize(Roles = Security.UserCategoryHelper.STAFF_CATEGORY)]
        public HttpResponseMessage Get(string onlyMine)
        {
            List<SlimLoanable> loanables = SlimLoanable.SlimGetLoanablesByOwner(User.UserId);
            return Request.CreateResponse<IEnumerable<SlimLoanable>>(HttpStatusCode.OK, loanables);


            //List<LoanableModel> loanableModels = new List<LoanableModel>();
            //List<Loanable> all = Loanable.getLoanablesByOwner(User.UserId);
            //foreach (Loanable loanable in all)
            //{
            //    LoanableModel model = new LoanableModel();
            //    model.Loanable = loanable;
            //    model.CurrentLoan = Loan.getCurrentActiveLoanForLoanable(loanable.LoanableId);

            //    loanableModels.Add(model);
            //}

            //return Request.CreateResponse<IEnumerable<LoanableModel>>(HttpStatusCode.OK, loanableModels);
        }

        /// <summary>
        /// recalls a loanable
        /// </summary>
        /// <param name="id">has to be "recall"</param>
        /// <param name="val">the loanable id</param>
        /// <returns></returns>
        [Security.BasicAuthorize(Roles = Security.UserCategoryHelper.STAFF_CATEGORY)]
        public HttpResponseMessage Put(string id, int val)
        {
            Loanable loanable = Loanable.getById(val);

            if (loanable != null)
            {
                if (id == "recall")
                {
                    if (loanable.Owner.UserId == User.UserId)
                    {
                        Loanable.OwnerRecall(loanable.LoanableId);
                        return Request.CreateResponse(HttpStatusCode.OK);
                    }
                    else
                    {
                        return Request.CreateResponse(HttpStatusCode.Forbidden);
                    }
                }
                else if (id == "markAsAvailable")
                {
                    if (loanable.Owner.UserId == User.UserId && !loanable.Owner.IsPendingExpiration)
                    {
                        if (loanable.markAsAvailable())
                        {
                            return Request.CreateResponse(HttpStatusCode.OK);
                        }
                        else
                        {
                            return Request.CreateResponse(HttpStatusCode.InternalServerError);
                        }
                    }
                    else
                    {
                        return Request.CreateResponse(HttpStatusCode.Forbidden);
                    }
                }
                else
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
        }

        /// <summary>
        /// adds a new loanable
        /// </summary>
        /// <returns></returns>
        [DoeLibsMVC.Filter.ValidateModel]
        [Security.BasicAuthorize(Roles = Security.UserCategoryHelper.STAFF_CATEGORY)]
        public HttpResponseMessage Post(EditLoanableModel model)
        {

            if (string.IsNullOrEmpty(model.ISBN10) && string.IsNullOrEmpty(model.ISBN13))
            {
                ModelState.AddModelError("ISBN10", "At least one ISBN number must be specified.");
                ModelState.AddModelError("ISBN13", "At least one ISBN number must be specified.");
            }

            if (!string.IsNullOrEmpty(model.Barcode) && Loanable.getLoanablesByDoelibsIdentifier(model.Barcode) != null)
            {
                ModelState.AddModelError("Barcode", "This DoeLibS identity is already in use");
            }

            if (ModelState.IsValid)
            {
                //Creates a new title if its not found
                Title title = null;
                if ((title = Title.getByIsbn10(model.ISBN10)) == null && (title = Title.getByIsbn13(model.ISBN13)) == null)
                {
                    title = new Title();
                    title.BookTitle = model.Title;
                    title.ISBN10 = model.ISBN10;
                    title.ISBN13 = model.ISBN13;
                    title.EditionNumber = model.Edition;
                    title.EditionYear = model.PublicationYear;
                    title.FirstEditionYear = model.FirstEditionYear;
                    title.Publisher = model.PublisherObject;


                    //save only title, if publisher could be created
                    if (title.Publisher.PublisherId > 0)
                    {
                        if (title.save())
                        {
                            foreach (Author a in model.AuthorList)
                            {
                                Title.addAuthor(a.Aid, title.TitleId, false);
                            }

                            foreach (Author editor in model.EditorList)
                            {
                                Title.addAuthor(editor.Aid, title.TitleId, true);
                            }

                            foreach (Topic t in model.TopicList)
                            {
                                Title.addTopic(t.TopicId, title.TitleId);
                            }
                        }
                    }
                }

                if (title != null && title.TitleId > 0) //only if the title was saved successfuly
                {
                    //Create the loanable and link it
                    Loanable loanable = new Loanable();

                    loanable.Barcode = model.Barcode;
                    loanable.Category = model.CategoryObject;
                    loanable.Location = model.Location;
                    loanable.Owner = this.User;
                    loanable.Title = title;

                    if (loanable.save())
                    {
                        //base.Message = new HttpMessage("Loanable was added.", true);
                        //return RedirectToAction("Get", "Title", new { id = title.TitleId });

                        HttpResponseMessage response = Request.CreateResponse<Loanable>(HttpStatusCode.Created, loanable);
                        response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = loanable.LoanableId }));

                        return response;
                    }
                    else
                    {
                        //base.Message = new HttpMessage("Loanable could not be added.", false);
                        return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Loanable could not be added");
                    }
                }
                else
                {
                    //base.Message = new HttpMessage("Loanable could not be added because it could not be linked with the title.", false);
                    return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Loanable could not be added because it could not be linked with the title.");
                }
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, FilterHelper.makeErrorsNice(ModelState));
            }
        }

        /// <summary>
        /// checks a loanable out
        /// </summary>
        /// <param name="id">loanableId</param>
        /// <returns></returns>
        [Security.BasicAuthorize]
        public HttpResponseMessage Post(int id)
        {
            Loanable loanable = Loanable.getById(id);

            if (loanable != null)
            {

                if (Loan.getLoansFromOwner(User.UserId).Where(l => l.Loanable.Title.TitleId == loanable.Title.TitleId && l.ReturnDate == DateTime.MinValue).ToList().Count == 0)
                {
                    Loan loan = loanable.checkOut(User);
                    if (loan != null)
                    {
                        return Request.CreateResponse<Loan>(HttpStatusCode.Created, loan);
                    }
                    else
                    {
                        return Request.CreateResponse(HttpStatusCode.BadRequest); //could be a reservation, loanable not available, etc.
                    }
                }
                else
                {
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "User has currently a loan with this title");
                }
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
        }


        /// <summary>
        /// updates a loanable from a title
        /// </summary>
        /// <param name="id">the loanableId</param>
        /// <param name="model"></param>
        /// <returns></returns>
        [DoeLibsMVC.Filter.ValidateModel]
        [Security.BasicAuthorize(Roles = Security.UserCategoryHelper.STAFF_CATEGORY)]
        public HttpResponseMessage Put(int id, EditLoanableModel model)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// deletes a loanable
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Security.BasicAuthorize(Roles = Security.UserCategoryHelper.STAFF_CATEGORY)]
        public HttpResponseMessage Delete(int id)
        {
			Loanable loanable = Loanable.getById(id);
			if (loanable != null)
			{
				Loanable.delete(loanable);
				return Request.CreateResponse(HttpStatusCode.OK);
			}
			else 
			{
				return Request.CreateResponse(HttpStatusCode.NotFound);
			}
        }

        /// <summary>
        /// Gets returns loanables by doelibsIdentifier
        /// </summary>
        /// <param name="String Identifier"></param>
        /// <returns></returns>
        public HttpResponseMessage GetLoanablesByDoeLibID(string doeLibId)
        {
			if (String.IsNullOrEmpty(doeLibId)) return Request.CreateResponse(HttpStatusCode.NotFound);
            Loanable loanable = Loanable.getLoanablesByDoelibsIdentifier(doeLibId);
            if (loanable != null)
            {
                return Request.CreateResponse<Loanable>(HttpStatusCode.OK, loanable);
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
        }

        /// <summary>
        /// Creates a new and unique doelibs identifier
        /// </summary>
        /// <param name="String Identifier"></param>
        /// <returns></returns>
        /// 
        public HttpResponseMessage GetNewIdentifier(string generateFreeDoeLibsId)
        {
            return Request.CreateResponse<String>(HttpStatusCode.OK, Loanable.getFreeBarcode());
        } 
    }
}
